package com.deluxelx.soul.inn.service.question.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deluxelx.soul.inn.bean.question.Answer;
import com.deluxelx.soul.inn.bean.question.AnswerParam;
import com.deluxelx.soul.inn.bean.question.AnswerVO;
import com.deluxelx.soul.inn.bean.question.Question;
import com.deluxelx.soul.inn.bean.question.QuestionDetailVO;
import com.deluxelx.soul.inn.bean.question.QuestionParam;
import com.deluxelx.soul.inn.bean.question.QuestionVO;
import com.deluxelx.soul.inn.bean.question.Tag;
import com.deluxelx.soul.inn.bean.user.User;
import com.deluxelx.soul.inn.common.param.CollectedParam;
import com.deluxelx.soul.inn.common.util.DateTimeUtil;
import com.deluxelx.soul.inn.common.util.RedisUtil;
import com.deluxelx.soul.inn.common.util.supportIds.SnowflakeId;
import com.deluxelx.soul.inn.mapper.common.IndexDataSupport;
import com.deluxelx.soul.inn.mapper.question.QuestionMapper;
import com.deluxelx.soul.inn.service.common.FollowRelationService;
import com.deluxelx.soul.inn.service.question.AnswerDaoExt;
import com.deluxelx.soul.inn.service.question.QuestionService;
import com.deluxelx.soul.inn.service.question.TagDaoExt;
import com.deluxelx.soul.inn.service.user.UserDaoExt;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static com.deluxelx.soul.inn.common.constant.IndexType.QUESTION;
import static com.deluxelx.soul.inn.common.constant.QuestionConstant.*;

/**
 * 问答服务实现类
 *
 * @author: zihao.liao
 * @date: 2024/1/16 17:24
 */
@Service
@Slf4j
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question> implements QuestionService {

    @Resource
    private UserDaoExt userDaoExt;

    @Resource
    private AnswerDaoExt answerDaoExt;

    @Resource
    private IndexDataSupport indexDataSupport;

    @Resource
    private FollowRelationService followRelationService;

    @Resource
    private TagDaoExt tagDaoExt;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private SnowflakeId snowflake;

    @Override
    public List<QuestionVO> fetchIndexQuestionList() {
        List<String> questionIndexIds = indexDataSupport.selectIndexDataByType(QUESTION);
        if (CollectionUtil.isEmpty(questionIndexIds)) {
            return Collections.emptyList();
        }
        List<Question> questionList = (List<Question>) this.listByIds(questionIndexIds);
        questionList.forEach(item -> {
            String title = item.getTitle();
            if (title.length() > 16) {
                item.setTitle(title.substring(0, 16) + "...");
            }
        });
        return buildStandardQuestionVO(questionList);
    }

    @Override
    public List<QuestionVO> fetchSearchQuestionList(String keyword) {
        List<Question> questionList = this.lambdaQuery()
                .like(StrUtil.isNotBlank(keyword), Question::getTitle, keyword)
                .orderByDesc(Question::getCreateTime)
                .eq(Question::getDeleteFlag, 0)
                .list();
        return buildStandardQuestionVO(questionList);
    }

    @Override
    public List<QuestionVO> fetchQuestionList() {
        List<Question> questionList = this.lambdaQuery()
                .orderByDesc(Question::getCreateTime)
                .eq(Question::getDeleteFlag, 0)
                .list();
        return buildStandardQuestionVO(questionList);
    }

    @Override
    public List<QuestionVO> fetchMyQuestionList(String userId) {
        if (StrUtil.isBlank(userId)) {
            log.error("用户ID不能为空");
            return Collections.emptyList();
        }
        List<Question> questionList = this.lambdaQuery()
                .eq(Question::getCreateUser, userId)
                .eq(Question::getDeleteFlag, 0)
                .orderByDesc(Question::getCreateTime)
                .list();
        return buildStandardQuestionVO(questionList);
    }

    @Override
    public List<QuestionVO> fetchMyFollowQuestionList(String userId) {
        List<String> questionIds = followRelationService.getMyFollowIds(userId, QUESTION_FOLLOW_KEY);
        if (CollectionUtil.isEmpty(questionIds)) {
            return Collections.emptyList();
        }
        List<Question> questionList = (List<Question>) this.listByIds(questionIds);
        return buildStandardQuestionVO(questionList);
    }

    @Override
    public List<Tag> fetchTagList() {
        String key = TAG_CACHE_KEY;
        String tagArrJson = redisUtil.get(key, String.class);
        List<Tag> tagListCache = JSONArray.parseArray(tagArrJson, Tag.class);
        if (tagListCache != null) {
            return tagListCache;
        }
        List<Tag> tagList = tagDaoExt.lambdaQuery().eq(Tag::getDeleteFlag, 0).list();
        String tagListJson = JSONArray.toJSONString(tagList);
        redisUtil.set(key, tagListJson);
        return tagList;
    }

    @Override
    public Boolean addMyQuestion(QuestionParam questionParam) {
        Question question = new Question();
        LocalDateTime now = LocalDateTime.now();
        question.setId(snowflake.nextStrId());
        question.setTitle(questionParam.getTitle());
        question.setType(questionParam.getType());
        question.setText(questionParam.getText());
        question.setTag(questionParam.getTag());
        question.setCreateTime(now);
        question.setCreateUser(questionParam.getUserId());
        question.setUpdateTime(now);
        question.setUpdateUser(questionParam.getUserId());
        return this.save(question);
    }

    @Override
    public QuestionDetailVO fetchQuestionDetail(String questionId) {
        if (StrUtil.hasBlank(questionId)) {
            return null;
        }
        Question question = this.lambdaQuery()
                .eq(Question::getId, questionId)
                .eq(Question::getDeleteFlag, 0)
                .one();
        QuestionDetailVO questionDetailVO = new QuestionDetailVO();
        BeanUtil.copyProperties(question, questionDetailVO);
        questionDetailVO.setCreateTimeStr(DateTimeUtil.getStandardDateTime(question.getCreateTime()));

        String authorId = question.getCreateUser();
        User user = userDaoExt.getById(authorId);
        questionDetailVO.setAuthorName(user.getNickName());
        questionDetailVO.setAuthorAvatar(user.getAvatar());

        List<Answer> answerList = answerDaoExt.lambdaQuery()
                .eq(Answer::getQuestionId, questionId)
                .eq(Answer::getDeleteFlag, 0)
                .orderByDesc(Answer::getAnswerTime)
                .list();
        questionDetailVO.setAnswerCount(answerList.size());
        List<AnswerVO> answerVOList = buildStandardAnswerVO(answerList, authorId);
        questionDetailVO.setAnswerList(answerVOList);
        int readNum;
        String key = buildReadQuestionKey(questionId);
        if (redisUtil.hasKey(key)) {
            readNum = (int) redisUtil.incr(key, 1);
            redisUtil.expire(key, QUESTION_CACHE_EXPIRE_TIME);
        } else {
            readNum = question.getReadNum() + 1;
            redisUtil.set(key, question.getReadNum() + 1, QUESTION_CACHE_EXPIRE_TIME);
        }
        questionDetailVO.setReadNum(readNum);
        return questionDetailVO;
    }

    @Override
    public Boolean addAnswer(AnswerParam answerParam) {
        Answer answer = new Answer();
        answer.setId(snowflake.nextStrId());
        answer.setQuestionId(answerParam.getQuestionId());
        answer.setAnswererId(answerParam.getAnswererId());
        answer.setAnswerContent(answerParam.getAnswerContent());
        answer.setAnswerTime(LocalDateTime.now());
        return answerDaoExt.save(answer);
    }

    @Override
    public List<AnswerVO> fetchAnswerList(String questionId) {
        if (StrUtil.isBlank(questionId)) {
            return Collections.emptyList();
        }
        Question question = this.lambdaQuery()
                .eq(Question::getId, questionId)
                .eq(Question::getDeleteFlag, 0)
                .one();
        List<Answer> answerList = answerDaoExt.lambdaQuery()
                .eq(Answer::getQuestionId, questionId)
                .eq(Answer::getDeleteFlag, 0)
                .orderByDesc(Answer::getAnswerTime)
                .list();
        return buildStandardAnswerVO(answerList, question.getCreateUser());
    }

    @Override
    public Boolean removeMyQuestion(String questionId) {
        if (StrUtil.isBlank(questionId)) {
            return false;
        }
        return this.lambdaUpdate()
                .set(Question::getDeleteFlag, 1)
                .eq(Question::getId, questionId)
                .update();
    }

    @Override
    public Boolean removeMyAnswer(String answerId) {
        if (StrUtil.isBlank(answerId)) {
            return false;
        }
        return answerDaoExt.lambdaUpdate()
                .set(Answer::getDeleteFlag, 1)
                .eq(Answer::getId, answerId)
                .update();
    }

    @Override
    public Boolean isLikeQuestion(CollectedParam param) {
        if (param == null || StrUtil.isEmpty(param.getUserId()) || StrUtil.isEmpty(param.getQuestionId())) {
            return Boolean.FALSE;
        }
        String key = buildFollowQuestionKey(param);
        Integer flag = redisUtil.get(key, Integer.class);
        if (null == flag) {
            Integer isSuccess = followRelationService.checkFollow(param);
            if (isSuccess > 0) {
                redisUtil.set(key, 1, QUESTION_CACHE_EXPIRE_TIME);
                return Boolean.TRUE;
            } else {
                return Boolean.FALSE;
            }
        } else if (0 == flag) {
            return Boolean.FALSE;
        } else if (1 == flag) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    @Override
    public Boolean likeQuestion(CollectedParam param) {
        if (param == null || StrUtil.isEmpty(param.getUserId()) || StrUtil.isEmpty(param.getQuestionId())) {
            return Boolean.TRUE;
        }
        try {
            String key1 = buildFollowQuestionKey(param);
            boolean bool1 = redisUtil.set(key1, 1, QUESTION_CACHE_EXPIRE_TIME);
            String key2 = buildFollowQuestionKey(param.getQuestionId());
            boolean bool2;
            if (redisUtil.hasKey(key2)) {
                redisUtil.incr(key2, 1);
                bool2 = redisUtil.expire(key2, QUESTION_CACHE_EXPIRE_TIME);
            } else {
                Question question = this.getById(param.getQuestionId());
                if (null == question) {
                    return Boolean.FALSE;
                }
                bool2 = redisUtil.set(key2, question.getLikeNum() + 1, QUESTION_CACHE_EXPIRE_TIME);
            }
            return bool1 && bool2;
        } catch (Exception e) {
            log.error("点赞心理问答失败：" + e.getMessage());
            return Boolean.FALSE;
        }
    }

    @Override
    public Boolean unLikeQuestion(CollectedParam param) {
        if (param == null || StrUtil.isEmpty(param.getUserId()) || StrUtil.isEmpty(param.getQuestionId())) {
            return Boolean.FALSE;
        }
        try {
            String key1 = buildFollowQuestionKey(param);
            boolean bool1 = false;
            String key2 = buildFollowQuestionKey(param.getQuestionId());
            if (!redisUtil.hasKey(key1)) {
                Integer isSuccess = followRelationService.checkFollow(param);
                if (isSuccess > 0) {
                    bool1 = redisUtil.set(key1, 0, QUESTION_CACHE_EXPIRE_TIME);
                }
            } else {
                bool1 = redisUtil.set(key1, 0, QUESTION_CACHE_EXPIRE_TIME);
            }
            if (!bool1) {
                return Boolean.FALSE;
            }
            if (redisUtil.hasKey(key2)) {
                redisUtil.decr(key2, 1);
                return redisUtil.expire(key2, QUESTION_CACHE_EXPIRE_TIME);
            } else {
                Question question = this.getById(param.getQuestionId());
                if (null == question) {
                    return Boolean.FALSE;
                }
                return redisUtil.set(key2, question.getLikeNum() - 1, QUESTION_CACHE_EXPIRE_TIME);
            }
        } catch (Exception e) {
            log.error("取消心理问答点赞失败：" + e.getMessage());
            return Boolean.FALSE;
        }
    }

    private List<QuestionVO> buildStandardQuestionVO(List<Question> questionList) {
        List<QuestionVO> questionVOList = new ArrayList<>();
        questionList.forEach(item -> {
            QuestionVO questionVO = new QuestionVO();
            BeanUtil.copyProperties(item, questionVO);
            questionVO.setCreateTimeStr(DateTimeUtil.getTimeForHuman(item.getCreateTime()));
            Integer likeNum = redisUtil.get(buildFollowQuestionKey(item.getId()), Integer.class);
            if (null != likeNum) {
                questionVO.setLikeNum(likeNum);
            }
            Integer readNum = redisUtil.get(buildReadQuestionKey(item.getId()), Integer.class);
            if (null != readNum) {
                questionVO.setReadNum(readNum);
            }
            questionVOList.add(questionVO);
        });
        return questionVOList;
    }

    private List<AnswerVO> buildStandardAnswerVO(List<Answer> answerList, String authorId) {
        List<AnswerVO> answerVOList = new ArrayList<>();
        answerList.forEach(item -> {
            String answererId = item.getAnswererId();
            AnswerVO answerVO = new AnswerVO();
            BeanUtil.copyProperties(item, answerVO);
            User user = userDaoExt.getById(answererId);
            answerVO.setAnswerName(user.getNickName());
            answerVO.setAnswerAvatar(user.getAvatar());
            answerVO.setAnswerTimeStr(DateTimeUtil.getStandardDate(item.getAnswerTime()));
            if (answererId.equals(authorId)) {
                answerVO.setAuthorFlag(1);
            } else {
                answerVO.setAuthorFlag(0);
            }
            answerVOList.add(answerVO);
        });
        return answerVOList;
    }
}
